package cn.jasonone.jfx.context;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReflectUtil;
import javafx.beans.property.Property;
import javafx.scene.control.Control;

import java.lang.reflect.Field;

/**
 * 控件绑定处理器
 *
 * @author xujie
 * @version 1.0
 * @date 2021/12/22 15:37
 */
public class BindPropertyUtil {
    private static Object getControlAttributeValue(Control node, String attributeName) {
        Control control = node;
        Class<? extends Control> controlClass = control.getClass();
        Assert.notBlank(attributeName, "控件默认属性不能为空,请检查[{}]控件是否拥有默认值处理器!", controlClass.getName());
        return ReflectUtil.getFieldValue(control, attributeName);
    }
    /**
     * 对控件的指定属性进行双向绑定
     *
     * @param control   控件
     * @param attribute 控件的属性名称
     * @param property  待绑定对象
     */
    public static void bind(Control control, String attribute, Property property) {
        Property fieldValue = (Property) getControlAttributeValue(control, attribute);
        fieldValue.bindBidirectional(property);
    }

    /**
     * 将对象的指定属性与控件的指定属性绑定<br>
     * 如果对象的类型为{@link Property}且不为null,则进行双向绑定;
     * 否则进行单项绑定,使对象属性值跟随控件值
     *
     * @param control   控件
     * @param attribute 控件的属性名称
     * @param target    待绑定对象
     * @param fieldName 待绑定对象的属性名称
     */
    public static void bind(Control control, String attribute, Object target, String fieldName) {
        Property attributeValue = (Property) getControlAttributeValue(control, attribute);
        Field field = ReflectUtil.getField(target.getClass(), fieldName);
        if (Property.class.isAssignableFrom(field.getType())) {
            Object fieldValue = ReflectUtil.getFieldValue(target, field);
            if (fieldValue != null) {
                bind(control, attribute, (Property) fieldValue);
            }
        } else {
            attributeValue.addListener((observable, oldValue, newValue) -> {
                ReflectUtil.setFieldValue(target, field, newValue);
            });
        }

    }
}
